package plugin

import (
	"context"

	"gitee.com/mkwchecking/k-scaffold/cmd/internal/flags"
	"gitee.com/mkwchecking/k-scaffold/config"
	"gitee.com/mkwchecking/k-scaffold/pkg/rely/log"
	remote "github.com/go-kratos/kratos/contrib/config/etcd/v2"
	kconfig "github.com/go-kratos/kratos/v2/config"
	"github.com/go-kratos/kratos/v2/config/file"
	"github.com/spf13/cobra"
	etcdctl "go.etcd.io/etcd/client/v3"
	"google.golang.org/grpc"
)

func InitConfig(c context.Context, cmd *cobra.Command) (context.Context, kconfig.Config, *config.Config, error) {
	configPath := cmd.Flag(flags.FlagConfig.Name).Value.String()
	if configPath == "" {
		panic("config file must be specified")
	}

	cm := new(config.Config)
	configResources := []kconfig.Source{file.NewSource(configPath)}

	if cmd.Flags().Lookup(flags.FlagRemoteConfigEnable.Name) != nil { // enable remote config
		enableRemote, err := cmd.Flags().GetBool(flags.FlagRemoteConfigEnable.Name)
		if err != nil {
			panic(err)
		}

		if enableRemote {
			remoteConfigEndpoints, err := cmd.Flags().GetStringSlice(flags.FlagRemoteConfigEndpoints.Name)
			if err != nil {
				panic(err)
			}
			remoteConfigTimeout, err := cmd.Flags().GetDuration(flags.FlagRemoteConfigTimeout.Name)
			if err != nil {
				panic(err)
			}
			remoteConfigPathPrefix, err := cmd.Flags().GetString(flags.FlagRemoteConfigPathPrefix.Name)
			if err != nil {
				panic(err)
			}

			client, err := etcdctl.New(etcdctl.Config{
				Endpoints:   remoteConfigEndpoints,
				DialTimeout: remoteConfigTimeout,
				DialOptions: []grpc.DialOption{grpc.WithBlock()},
			})
			if err != nil {
				panic(err)
			}
			remoteSource, err := remote.New(
				client,
				remote.WithContext(cmd.Context()),
				remote.WithPath(remoteConfigPathPrefix),
				remote.WithPrefix(true),
			)
			if err != nil {
				panic(err)
			}
			configResources = append(configResources, remoteSource)
		}
	}

	src := kconfig.New(kconfig.WithSource(configResources...))
	if err := src.Load(); err != nil {
		panic(err)
	}
	if err := src.Scan(cm); err != nil {
		panic(err)
	}

	config.SetConfig(cm)

	c = config.SetToContext(c, cm)
	return c, src, cm, nil
}

func WatchConfig(log *log.Logger, source kconfig.Config, cm *config.Config) error {
	return config.Watch(log.Logger, source, cm)
}
